#include "GAF_Bundle.h"

namespace GAF
{
	Bundle::Bundle()
	{
	}

	Bundle::Bundle(const Bundle& bdlSrc)
	{
		Copy(&bdlSrc);
	}

	Bundle::~Bundle()
	{
		Clear();
	}

	Pointer Bundle::Foreach(bool bFirst)
	{
		if(bFirst)
			m_itForeach = m_mapArgs.begin();
		else
			m_itForeach++;

		if(m_itForeach == m_mapArgs.end())
			return NULL;

		return (Pointer)&(m_itForeach->first);
	}

	UINT Bundle::GetCount()
	{
		return m_mapArgs.size();
	}

	void Bundle::Clear()
	{
		if(m_mapArgs.size() > 0)
		{
			Var _Arg = {NULL, VAR_UNKOWN};


			for(VarMap::iterator _it = m_mapArgs.begin();
				_it != m_mapArgs.end(); _it++)
			{
				_Arg = _it->second;
				_it->second.pVar = NULL;

				if(_Arg.pVar != NULL)
				{
					if(_Arg.type == VAR_CHARS)
					{
						GAF_DELETE_ARY(_Arg.pVar);
					}
					else
					{
						GAF_DELETE(_Arg.pVar);
					}
				}
			}

			m_mapArgs.clear();
		}
	}

	void Bundle::operator=(const Bundle& bdlSrc)
	{
		Clear();
		Copy(&bdlSrc);
	}

	Bundle Bundle::operator+(const Bundle& bdlSrc)
	{
		Bundle bdlRtn;
		bdlRtn.Copy(this);
		bdlRtn.Copy(&bdlSrc);
		return bdlRtn;
	}

	void Bundle::operator+=(const Bundle& bdlSrc)
	{
		Copy(&bdlSrc);
	}

	bool Bundle::operator==(Bundle& bdlOther)
	{
		if(GetCount() == bdlOther.GetCount())
		{
			VarMap::const_iterator _cit = m_mapArgs.begin();

			for(VarMap::const_iterator _cit = m_mapArgs.begin();
				_cit != m_mapArgs.end(); _cit++)
			{
				Var& _arg = bdlOther.FindArg(_cit->first);

				if(_arg.pVar == NULL && _arg.type == VAR_UNKOWN)
					break;

				if(_arg.pVar != _cit->second.pVar || _arg.type != _cit->second.type)
					break;
			}

			return true;
		}

		return false;
	}

	bool Bundle::operator!=(Bundle& bdlOther)
	{
		return !(operator==(bdlOther));
	}

	bool Bundle::PutBoolean(STD_STRING strKey, bool b)
	{
		bool isReturn;

		bool* _pb = GAF_NEW(bool);
		*_pb = b;

		if(FindArg(strKey).pVar == NULL)
			isReturn = PutArg(strKey, (Pointer)_pb, VAR_BOOLEAN);
		else
			isReturn = ChangeArg(strKey, (Pointer)_pb, VAR_BOOLEAN);

		if(!isReturn)
		{
			GAF_ERRMARK();
		}

		return isReturn;
	}

	bool Bundle::PutInteger(STD_STRING strKey, int n)
	{
		bool isReturn;

		int* _pn = GAF_NEW(int);
		*_pn = n;

		if(FindArg(strKey).pVar == NULL)
			isReturn = PutArg(strKey, (Pointer)_pn, VAR_INTEGER);
		else
			isReturn = ChangeArg(strKey, (Pointer)_pn, VAR_INTEGER);

		if(!isReturn)
		{
			GAF_ERRMARK();
		}

		return isReturn;
	}

	bool Bundle::PutLong(STD_STRING strKey, long l)
	{
		bool isReturn;

		long* _pl = GAF_NEW(long);
		*_pl = l;

		if(FindArg(strKey).pVar == NULL)
			isReturn = PutArg(strKey, (Pointer)_pl, VAR_LONG);
		else
			isReturn = ChangeArg(strKey, (Pointer)_pl, VAR_LONG);

		if(!isReturn)
		{
			GAF_ERRMARK();
		}

		return isReturn;
	}

	bool Bundle::PutFloat(STD_STRING strKey, float f)
	{
		bool isReturn;

		float* _pf = GAF_NEW(float);
		*_pf = f;

		if(FindArg(strKey).pVar == NULL)
			isReturn = PutArg(strKey, (Pointer)_pf, VAR_FLORT);
		else
			isReturn = ChangeArg(strKey, (Pointer)_pf, VAR_FLORT);

		if(!isReturn)
		{
			GAF_ERRMARK();
		}

		return isReturn;
	}

	bool Bundle::PutDouble(STD_STRING strKey, double d)
	{
		bool isReturn;

		double* _pd = GAF_NEW(double);
		*_pd = d;

		if(FindArg(strKey).pVar == NULL)
			isReturn = PutArg(strKey, (Pointer)_pd, VAR_DOUBLE);
		else
			isReturn = ChangeArg(strKey, (Pointer)_pd, VAR_DOUBLE);

		if(!isReturn)
		{
			GAF_ERRMARK();
		}

		return isReturn;
	}

	bool Bundle::PutChars(STD_STRING strKey, char* sz)
	{
		bool isReturn;

		char* _psz = GAF_NEW_ARY(char, SYS_STRLEN(sz));
		SYS_STRCPY(_psz, sz);

		if(FindArg(strKey).pVar == NULL)
			isReturn = PutArg(strKey, (Pointer)_psz, VAR_CHARS);
		else
			isReturn = ChangeArg(strKey, (Pointer)_psz, VAR_CHARS);

		if(!isReturn)
		{
			GAF_ERRMARK();
		}

		return isReturn;
	}

	bool Bundle::PutString(STD_STRING strKey, STD_STRING str)
	{
		bool isReturn;

		STD_STRING* _pstr = GAF_NEW(STD_STRING);
		_pstr->assign(str);

		if(FindArg(strKey).pVar == NULL)
			isReturn = PutArg(strKey, (Pointer)_pstr, VAR_STRING);
		else
			isReturn = ChangeArg(strKey, (Pointer)_pstr, VAR_STRING);

		if(!isReturn)
		{
			GAF_ERRMARK();
		}

		return isReturn;
	}

	bool Bundle::PutPointer(STD_STRING strKey, Pointer p)
	{
		bool isReturn;

		Pointer* _pp = GAF_NEW(Pointer);
		*_pp = p;

		if(FindArg(strKey).pVar == NULL)
			isReturn = PutArg(strKey, (Pointer)_pp, VAR_POINTER);
		else
			isReturn = ChangeArg(strKey, (Pointer)_pp, VAR_POINTER);

		if(!isReturn)
		{
			GAF_ERRMARK();
		}

		return isReturn;
	}

	bool Bundle::PutAgent(STD_STRING strKey, Agent a)
	{
		bool isReturn;

		Agent* _pa = GAF_NEW_PRM(Agent, (NULL, NULL));
		*_pa = a;

		if(FindArg(strKey).pVar == NULL)
			isReturn = PutArg(strKey, (Pointer)_pa, VAR_POINTER);
		else
			isReturn = ChangeArg(strKey, (Pointer)_pa, VAR_POINTER);

		if(!isReturn)
		{
			GAF_ERRMARK();
		}

		return isReturn;
	}

	bool Bundle::GetBoolean(STD_STRING strKey)
	{
		m_ArgTemp = FindArg(strKey);
		if(m_ArgTemp.type != VAR_BOOLEAN)
		{
			return false;
		}

		return *(bool*)(m_ArgTemp.pVar);
	}

	int Bundle::GetInteger(STD_STRING strKey)
	{
		m_ArgTemp = FindArg(strKey);
		if(m_ArgTemp.type != VAR_INTEGER)
		{
			return 0;
		}

		return *(int*)(m_ArgTemp.pVar);
	}

	long Bundle::GetLong(STD_STRING strKey)
	{
		m_ArgTemp = FindArg(strKey);
		if(m_ArgTemp.type != VAR_LONG)
		{
			return 0;
		}

		return *(long*)(m_ArgTemp.pVar);
	}

	float Bundle::GetFloat(STD_STRING strKey)
	{
		m_ArgTemp = FindArg(strKey);
		if(m_ArgTemp.type != VAR_FLORT)
		{
			return 0;
		}

		return *(float*)(m_ArgTemp.pVar);
	}

	double Bundle::GetDouble(STD_STRING strKey)
	{
		m_ArgTemp = FindArg(strKey);
		if(m_ArgTemp.type != VAR_DOUBLE)
		{
			return 0;
		}

		return *(double*)(m_ArgTemp.pVar);
	}

	char* Bundle::GetChars(STD_STRING strKey)
	{
		m_ArgTemp = FindArg(strKey);
		if(m_ArgTemp.type != VAR_CHARS)
		{
			return 0;
		}

		return *(char**)(m_ArgTemp.pVar);
	}

	STD_STRING Bundle::GetString(STD_STRING strKey)
	{
		m_ArgTemp = FindArg(strKey);
		if(m_ArgTemp.type != VAR_STRING)
		{
			return "";
		}

		return *(STD_STRING*)(m_ArgTemp.pVar);
	}

	Pointer Bundle::GetPointer(STD_STRING strKey)
	{
		m_ArgTemp = FindArg(strKey);
		if(m_ArgTemp.type != VAR_POINTER)
		{
			return 0;
		}

		return *(Pointer*)(m_ArgTemp.pVar);
	}

	Agent Bundle::GetAgent(STD_STRING strKey)
	{
		m_ArgTemp = FindArg(strKey);
		if(m_ArgTemp.type != VAR_AGENT)
		{
			return Agent(NULL, NULL);
		}

		return *(Agent*)(m_ArgTemp.pVar);
	}

	Bundle::VarType Bundle::GetType( STD_STRING strKey )
	{
		return FindArg(strKey).type;
	}

	bool Bundle::Copy(const Bundle* pbdlSrc)
	{
		GAF_CHECK_R(pbdlSrc != NULL, false);

		for(VarMap::const_iterator _cit = pbdlSrc->m_mapArgs.begin();
			_cit != pbdlSrc->m_mapArgs.end(); _cit++)
		{
			STD_STRING _strKey = _cit->first;
			Var _Arg = _cit->second;

			switch(_Arg.type)
			{
			case VAR_BOOLEAN:
				PutBoolean(_strKey, *(bool*)(_Arg.pVar));
				break;
			case VAR_INTEGER:
				PutInteger(_strKey, *(int*)(_Arg.pVar));
				break;
			case VAR_LONG:
				PutLong(_strKey, *(long*)(_Arg.pVar));
				break;
			case VAR_FLORT:
				PutFloat(_strKey, *(float*)(_Arg.pVar));
				break;
			case VAR_DOUBLE:
				PutDouble(_strKey, *(double*)(_Arg.pVar));
				break;
			case VAR_CHARS:
				PutChars(_strKey, *(char**)(_Arg.pVar));
				break;
			case VAR_STRING:
				PutString(_strKey, *(STD_STRING*)(_Arg.pVar));
				break;
			case VAR_POINTER:
				PutPointer(_strKey, *(Pointer*)(_Arg.pVar));
				break;
			case VAR_AGENT:
				PutAgent(_strKey, *(Agent*)(_Arg.pVar));
				break;
			default:
				break;
			}
		}

		return true;
	}

	Bundle::Var& Bundle::FindArg(STD_STRING strKey)
	{
		static Var s_argNull = {NULL, VAR_UNKOWN};

		VarMap::iterator _it = m_mapArgs.find(strKey);
		if(_it == m_mapArgs.end())
			return s_argNull;

		return _it->second;
	}

	bool Bundle::PutArg(STD_STRING strKey, Pointer pArg, VarType kind)
	{
		Var _NewArg;
		_NewArg.pVar = pArg;
		_NewArg.type = kind;

		m_mapArgs.insert(VarMap::value_type(strKey, _NewArg));

		return true;
	}

	bool Bundle::ChangeArg(STD_STRING strKey, Pointer pArg, VarType kind)
	{
		Var& _arg = FindArg(strKey);
		if(_arg.type != kind)
		{
			return false;
		}

		GAF_DELETE(_arg.pVar);
		_arg.pVar = pArg;

		return true;
	}
}
